#include "Merge.h"
#include "Parser.h"
#include <stdio.h>
void Merge::ejecutarMerge(list<string> &lista_particiones , const string & directorioDestino) {
	cout<<"Merge"<<endl;
	unsigned int cantidadParticiones = lista_particiones.size();
	if(cantidadParticiones > 1){
		unsigned idAutorizado = 0;
		//aplico merge a todas las particiones
		while(lista_particiones.size()>1){
			//aplico merge a un grupo de particiones
			ejecutarMergeParcial(lista_particiones , directorioDestino , idAutorizado);
			idAutorizado ++;
		}
	}else{
		if(cantidadParticiones == 0){
			cout<<" -> Error: No existen entradas para el MERGE."<<endl;
		}
	}
	cout<<" Fin Merge"<<endl;
}

void Merge::ejecutarMergeParcial(list<string> &lista_particiones , const string & directorioDestino ,
								const unsigned int idAutorizado){
	list<string>::iterator iterador = lista_particiones.begin();
	vector<string> rutas;
	unsigned int cantidadRutas = 0;
	unsigned int partProc = 0;
	while((partProc < VIAS_ENTRADA_MERGE) && (iterador != lista_particiones.end()) ){
		rutas.push_back(*iterador);
		iterador++;
		cantidadRutas++;
		partProc++;
	}
	if(cantidadRutas > 1){
		// apertura de vías de entrada
		ifstream particiones[VIAS_ENTRADA_MERGE];
		unsigned cantidadParticiones = 0;
		for(unsigned int i= 0 ; i < cantidadRutas; i++){
			particiones[cantidadParticiones].open(rutas[i].c_str(),ios::in | ios::binary );
			if(particiones[cantidadParticiones].is_open()){
				cout<<rutas[i]<<" "<<endl;
				cantidadParticiones++;
			}
		}
		// agrego nuevo partición correspondiente a la vía de sálida
		string rutaSalida;
		rutaSalida.append(directorioDestino);
		rutaSalida.append("/");
		rutaSalida.append(NOMBRE_PARTICIONES_MERGE);
		char buffer[33];
		memset(buffer, 0, 33);
		sprintf(buffer,"%d",idAutorizado);
		rutaSalida.append(buffer);
		ofstream salida;
		salida.open(rutaSalida.c_str(), ios::out | ios::binary);
		if(salida.is_open()){
			// agrego el nombre de la partición generada a la lista
			lista_particiones.push_back(rutaSalida);
			// merge propiamente dicho
			string terminos[VIAS_ENTRADA_MERGE];
			unsigned int documentos[VIAS_ENTRADA_MERGE];
			// carga inicial de datos
			Termino_Parseado registro;
			for(unsigned int i = 0 ; i < cantidadParticiones; i ++){
				particiones[i].read(reinterpret_cast<char*> (&registro),sizeof(Termino_Parseado));
				documentos[i] = registro.doc;
				terminos[i].assign(registro.termino);
				cout<<terminos[i]<<endl;
			}
			// ciclo de merge
			bool fin = false;
			while (!fin){
				cout<<"While"<<endl;
				//búsqueda de mínimo
				unsigned int minimo = 0;
				for(unsigned int i = 0; i < cantidadParticiones ; i++){
					if( !particiones[minimo].eof() ){
						unsigned int resCompCadenas = terminos[minimo].compare(terminos[i]);
						if(resCompCadenas == 0){
							if(documentos[minimo] > documentos[i]){
								minimo = i;
							}
						}else{
							if(resCompCadenas > 0 ){
								minimo = i;
							}
						}
					}else{
						minimo = i;
					}
				}
				fin = true;
				// grabo minimo
				if(particiones[minimo]){
					registro.doc = documentos[minimo];
					memcpy(registro.termino,terminos[minimo].c_str(), 40);
					salida.write(reinterpret_cast<char*> (&registro),sizeof(Termino_Parseado));
				}

				// evalución de condición de fin, la cual es que alguno no llego a fin
				for(unsigned int i = 0; i < cantidadParticiones ; i ++){
					if(particiones[i].eof()){
						fin &= particiones[i].eof();
						documentos[i] = 0;
						terminos[i].clear();
					}else{
						fin &= false;
					}
				}

				// avanzo mínimo
				particiones[minimo].read(reinterpret_cast<char*> (&registro),sizeof(Termino_Parseado));
				documentos[minimo] = registro.doc;
				terminos[minimo].assign(registro.termino);
			}
		}else{
			cout<<" -> ERROR: EN MERGE >> No se pudo generar partición sálida "<<rutaSalida<<endl;
		}
		// cierre de vías de entrada
		for(unsigned int i = 0 ; i < cantidadParticiones; i++){
			particiones[i].close();
		}
		salida.close();
		// eliminación de particiones
		for(unsigned int i= 0 ; i < cantidadRutas; i++){
			remove(rutas[i].c_str());
		}
	}
}
